#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include "timer.h"

#define DIM 10
#define NUM_OF_SHIPS 5

using namespace std;

void clearScreen();
void printBoard(char matrix[DIM][DIM], string matrixName);
int* setShip(int shipLenght, int x, int y, int direction, char matrix[DIM][DIM]);
int rand (int low, int high);
int* setShoot(int coord[2], char matrix[DIM][DIM]);
int* setShoot(int coord[2], char matrix[DIM][DIM], int* ships[NUM_OF_SHIPS]);
int* getShoot();
int* getRandShoot(int* ships[NUM_OF_SHIPS]);
int allShipsDestroyed(int* ships[NUM_OF_SHIPS]);

int main(){
    char myMatrix[DIM][DIM];
    char opMatrix[DIM][DIM];
    double start, finish, elapsed;
    
    int *coord1, *coord2;
    
    int* ships1[NUM_OF_SHIPS];
    int* ships2[NUM_OF_SHIPS];
    
    int flag1, flag2;

    int op=1;
    
    GET_TIME(start);
    
    srand(time(NULL));
    
    
    //set watter in all matrix
    for (int i=0; i<DIM; i++){
        for(int j=0; j<DIM; j++){
            myMatrix[i][j] = '~';
            opMatrix[i][j] = '~';
        }
    }
    
    ships1[0] = setShip(2, rand(0, 9), rand(0, 9), rand(0, 3), myMatrix);
    ships1[1] = setShip(3, rand(0, 9), rand(0, 9), rand(0, 3), myMatrix);
    ships1[2] = setShip(3, rand(0, 9), rand(0, 9), rand(0, 3), myMatrix);
    ships1[3] = setShip(4, rand(0, 9), rand(0, 9), rand(0, 3), myMatrix);
    ships1[4] = setShip(5, rand(0, 9), rand(0, 9), rand(0, 3), myMatrix);
    
    ships2[0] = setShip(2, rand(0, 9), rand(0, 9), rand(0, 3), opMatrix);
    ships2[1] = setShip(3, rand(0, 9), rand(0, 9), rand(0, 3), opMatrix);
    ships2[2] = setShip(3, rand(0, 9), rand(0, 9), rand(0, 3), opMatrix);
    ships2[3] = setShip(4, rand(0, 9), rand(0, 9), rand(0, 3), opMatrix);
    ships2[4] = setShip(5, rand(0, 9), rand(0, 9), rand(0, 3), opMatrix);
    
    printBoard(myMatrix, "Player 1");
    cout << endl;
    printBoard(opMatrix, "Player 2");
    cout << endl;

    while(1) {
        //cout << "My board" << endl;
        //coord1 = getShoot();
        coord1 = getRandShoot(ships2);
        setShoot(coord1, opMatrix, ships2);
        
        coord2 = getRandShoot(ships1);
        setShoot(coord2, myMatrix, ships1);
        
        
        
        for (int i=0; i<5; i++) {
            flag1 = 0;
            flag2 = 0;
            for (int j=1; j<=ships1[i][0]; j++) {
                if(ships1[i][j] >= 0) {
                    flag1 = 1;
                    break;
                }
            }
            
            if(flag1 == 0) {
                cout <<op<< " \nShip " << ships1[i][0] << " of Player 1 was destroyed."<<endl;
            }
            
            for (int j=1; j<=ships2[i][0]; j++) {
                if(ships2[i][j] >= 0) {
                    flag2 = 1;
                    break;
                }
            }
            
            if(flag2 == 0) {
                cout << "Ship " << ships1[i][0] << " of Player 2 was destroyed."<<endl;
            }
        }
        
        if ( allShipsDestroyed(ships2) == 1){
            cout << "All ships destroyed! Player 1 won!!"<<endl;
            printBoard(myMatrix, "Player 1");
            printBoard(opMatrix, "Player 2");
            break;
        }
        if ( allShipsDestroyed(ships1) == 1) {
            cout << "All ships destroyed! Player 2 won!!"<<endl;
            printBoard(myMatrix, "Player 1");
            printBoard(opMatrix, "Player 2");
            break;
        }
      op++;
    }
    
    GET_TIME(finish);
    elapsed = finish-start;
    
    cout << endl << "Time of execution: " << elapsed << "." << endl;
    
    return 0;
}

void clearScreen() {
    cout << string(100,'\n');
}

/* Print a board on the screen
 * @param matrix It's the board
 */
void printBoard(char matrix[DIM][DIM], string matrixName) {
    char row = 'A';
    
    cout << matrixName << endl;
    cout<<"  ";
    for(int j=0; j<DIM; j++)
        cout << j+1<<"  ";
    
    cout<<endl;
    
    for(int i=0; i<DIM; i++) {
        cout << row;
        for(int j=0; j<DIM; j++) {
            cout <<" "<< matrix[i][j]<<" ";
        }
        cout << endl;
        row = (int)row+1;
    }
}

/* Set a specifc ship on the board
 * @param shipLenght Lengh of a ship to set on the board
 * @param x              Represents a row of the board
 * @param y              Represents a collum of the board
 * @param direction  Direction to set a ship (0..3)
 * @param matrix         It's the board
 * @param Return an array with coordinates of ships
 * the first element is the lenght of the array and
 * all other elements are like 'rc' where r is the row
 * and c is the colum, so we need to divide the element by
 * 10*Dim = row and get the modulus by 10*dim and get the column
 */
int* setShip(int shipLenght, int x, int y, int direction, char matrix[DIM][DIM]) {
    int i, j, flag;
    int *ship = new int[shipLenght+1];
    
    ship[0] = shipLenght;
    
    if(direction == 0) {//Direction is up
        //Check if a ship can be set
        if((x-shipLenght+1) <0 || matrix[x][y]!='~')    {
            //ship cannot be set because there is no space to set
            delete(ship);
            setShip(shipLenght, x, y, 1, matrix);
        }
        else {
            flag = 0;
            //Check if there is anoter ship on the way
            for (i=x-shipLenght+1; i<=x; i++) {
                if(matrix[i][y] != '~') {
                    flag = 1;
                    break;
                }
            }
            if(flag == 0) {
                //There is space to set a ship
                for (i=x-shipLenght+1, j=1; i<=x; i++, j++) {
                    matrix[i][y] = (char) 48+shipLenght;
                    ship[j] = (10*DIM*i) + y;
                }
            }
            else {
                //There is no space to set a ship i this direction,
                //so try another one
                delete(ship);
                setShip(shipLenght, x, y, 1, matrix);
            }
        }
    }
    
    else if(direction == 1) { //Direction is left
        if((y-shipLenght+1) < 0 || matrix[x][y]!='~') {
            delete(ship);
            setShip(shipLenght, x, y, 2, matrix);
        }
        else {
            flag = 0;
            for (j=y-shipLenght+1; j<=y; j++) {
                if(matrix[x][j] != '~') {
                    flag = 1;
                    break;
                }
            }
            if(flag == 0) {
                for (j=y-shipLenght+1, i=1; j<=y; i++, j++) {
                    matrix[x][j] = (char)48+shipLenght;
                    ship[i] = (10*DIM*(x)) + (j);
                }
            }
            else {
                delete(ship);
                setShip(shipLenght, x, y, 2, matrix);
            }
        }
    }
    
    else if(direction == 2) {//Direction is down
        if((x+shipLenght-1)>=DIM || matrix[x][y] != '~') {
            delete(ship);
            setShip(shipLenght, x, y, 3, matrix);
        }
        else {
            flag = 0;
            for(i=x; i<= x+shipLenght-1; i++) {
                if(matrix[i][y] != '~') {
                    flag = 1;
                    break;
                }
            }
            if(flag == 0) {
                for(i=x, j=1; i<= x+shipLenght-1; i++, j++) {
                    matrix[i][y] =(char)48+shipLenght;
                    ship[j] = (10*DIM*(i))+(y);
                }
            }
            else {
                delete(ship);
                setShip(shipLenght, x, y, 3, matrix);
            }
        }
    }
    
    else if(direction == 3) { //Direction is right
        if((y+shipLenght-1)>=DIM || matrix[x][y] != '~'){
            delete(ship);
            setShip(shipLenght, rand(0, 9), rand(0, 9), 0, matrix);
        }
        else {
            flag = 0;
            for(j=y; j<=y+shipLenght-1; j++) {
                if(matrix[x][j] != '~') {
                    flag = 1;
                    break;
                }
            }
            if(flag == 0) {
                for(j=y, i=1; j<=y+shipLenght-1; i++, j++) {
                    matrix[x][j] = (char)48+ shipLenght;
                    ship[i] = (10*DIM*(x))+(j);
                }
            }
            else {
                delete(ship);
                setShip(shipLenght, rand(0,9), rand(0,9), 0, matrix);
            }
        }
    }
    else ship = NULL;
    return ship;
}

int rand(int low, int high) {
    return (rand()%(high-low+1))+low;
}

int allShipsDestroyed(int* ships[NUM_OF_SHIPS]) {
    int result = 0;
    
    for (int i=0; i<NUM_OF_SHIPS; i++) {
        for (int j=1; j<=ships[i][0]; j++) {
            if(ships[i][j]>= 0) result = 1;
        }
    }
    if(result == 0) {
        return 1;
    }
    else return 0;
}

int* setShoot(int coord[2], char matrix[DIM][DIM], int *ships[NUM_OF_SHIPS]) {
    int *shoot;
    shoot = new int[2];
    
    if (coord != NULL ) {
        if (matrix[coord[0]][coord[1]] == '~') {
            shoot[0] = coord[0];
            shoot[1] = coord[1];
        }
        
        else if (matrix[coord[0]][coord[1]] == 'x') {
            delete(shoot);
            coord = getRandShoot(ships);
            setShoot(coord, matrix, ships);
        }
        else {
            shoot[0] = coord[0];
            shoot[1] = coord[1];
        }
        matrix[coord[0]][coord[1]] = 'x';
    }
    return shoot;
}

/* Set a shoot in a matrix
 * @param result Return 1 for hit and 0 for miss
 */
int* setShoot(int coord[2], char matrix[DIM][DIM]) {
    int *shoot;
    shoot = new int[2];
    
    if (coord != NULL ) {
        if (matrix[coord[0]][coord[1]] == '~') {
            shoot[0] = coord[0];
            shoot[1] = coord[1];
        }
        
        else if (matrix[coord[0]][coord[1]] == 'x') {
            delete(shoot);
            coord = getShoot();
            setShoot(coord, matrix);
        }
        else {
            shoot[0] = coord[0];
            shoot[1] = coord[1];
        }
        matrix[coord[0]][coord[1]] = 'x';
    }
    return shoot;
}

/* Get a shoot made by a player
 * @param coord Return a coordinate [x, y]
 */
int* getShoot() {
    int* coord;
    int row = 0;
    int col = 0;
    char shoot;
    coord = new int(2);
    
    cout << "Enter where you want to shoot (row from A to J and colum from 0 to 10)" << endl;
    cout << "Example: A 10, B 5, J 1" << endl << "> ";
    
    cin >> shoot;
    cin >> col;
    
    row = (int) tolower(shoot);
    row -= 97;
    if(row >= DIM || row < 0) {
        cout << "Row out of range" << endl;
        delete(coord);
        coord = getShoot();
    }
    else if(col-1 >= DIM || col-1 < 0) {
        cout << "Colum out of range" << endl;
        delete(coord);
        coord = getShoot();
    }
    else {
        coord[0] = row;
        coord[1] = col-1;
    }
    return coord;
}

int* getRandShoot(int *ships[NUM_OF_SHIPS]) {
    int* coord;
    coord = new int(2);
    
    coord[0] = rand(0,9);
    coord[1] = rand(0,9);
    
    //Check if hit any ship
    for (int i=0; i<NUM_OF_SHIPS; i++) {
        for (int j=1; j<=ships[i][0]; j++) {
            if((coord[0] == ships[i][j]/(10*DIM)) && (coord[1] == ships[i][j]%(10*DIM))) {
                ships[i][j] = -1;
            }
        }
    }

    return coord;
}